pub mod bili;

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TagData {
    name: String,
    desc: String,
}

// impl From<SqliteRow> for TagData {
//     fn from(row: SqliteRow) -> Self {
//         Self {
//             name: row.get::<String, _>("name"),
//             desc: row.get::<String, _>("desc"),
//         }
//     }
// }

// impl CRUD<TagData> for TagData {
//     async fn create(&self, pool: &Pool<Sqlite>) -> SqliteQueryResult {
//         let sql = r#"
//         INSERT INTO tag
//         (name, desc)
//         VALUES (?, ?);
//         "#;
//         sqlx::query(sql)
//             .bind(&self.name)
//             .bind(&self.desc)
//             .execute(pool)
//             .await
//             .unwrap()
//     }
//
//     async fn read(pool: &Pool<Sqlite>) -> Vec<TagData> {
//         let sql = r#"
//         SELECT *
//         FROM tag;
//         "#;
//         if let Ok(rows) = sqlx::query(sql).fetch_all(pool).await {
//             rows.into_iter()
//                 .map(TagData::from)
//                 .collect::<Vec<TagData>>()
//         } else { vec![] }
//     }
//
//     async fn update(&self, pool: &Pool<Sqlite>) -> SqliteQueryResult {
//         let sql = r#"
//         UPDATE tag
//         SET name=?, desc=?
//         WHERE name=?;
//         "#;
//         sqlx::query(sql)
//             .bind(&self.name)
//             .bind(&self.desc)
//             .bind(&self.name)
//             .execute(pool)
//             .await
//             .unwrap()
//     }
//
//     async fn delete(&self, pool: &Pool<Sqlite>) -> SqliteQueryResult {
//         let sql = r#"
//         DELETE FROM tag
//         WHERE name=?;
//         "#;
//         sqlx::query(sql)
//             .bind(&self.name)
//             .execute(pool)
//             .await
//             .unwrap()
//     }
// }

impl TagData {
    pub fn new(name: &str, desc: &str) -> Self {
        Self {
            name: name.to_string(),
            desc: desc.to_string(),
        }
    }
}

#[cfg(test)]
mod test_tag_data {
    use crate::spider::TagData;

    fn test_serde() {
        let json_str = r#"
        {
            name: "test",
            desc: "test"
        }
        "#;
        let tag = serde_json::from_str::<TagData>(json_str).unwrap();
        assert_eq!(tag.name, "test");
        assert_eq!(tag.desc, "test");
        let json = serde_json::to_string(&tag).unwrap();
        assert_eq!(json, json_str);
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PictureData {
    pub src: String,
    pub path: String,
    pub width: i64,
    pub height: i64,
    pub size: f64,
    pub tags: Vec<TagData>,
}

impl PictureData {
    pub fn new(src: &str, path: &str, width: i64, height: i64, size: f64) -> Self {
        Self {
            src: src.to_string(),
            path: path.to_string(),
            width,
            height,
            size,
            tags: vec![],
        }
    }

    pub fn add_tag(mut self, tag: TagData) -> Self {
        self.tags.push(tag);
        self
    }

    pub fn remove_tag(mut self, name: &str) -> Self {
        let mut i = 0;
        for tag in &self.tags {
            if tag.name == name { break; }
            i += 1;
        }
        if i < self.tags.len() { self.tags.remove(i); }
        self
    }
}